package com.xcity.game.conquests;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;

import com.alibaba.fastjson.JSON;
import com.xcity.db.entity.Build;
import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Employee.State;
import com.xcity.db.entity.Player;
import com.xcity.game.buildv2.BuildV2;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.employee.EmployeeListener;
import com.xcity.game.io.SerializeStream;
import com.xcity.game.io.Serializer;
import com.xcity.game.io.SerializerUtils;
import com.xcity.game.mail.MailAttach;
import com.xcity.game.mail.MailService;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.push.SyncPush;
import com.xcity.pomelo.push.sync.IntSync;

import naga.x.App;
import naga.x.common.Updatable;
import naga.x.game.time.TimeUpdater;

public class Conquests implements Updatable, EmployeeListener, Serializer {

	protected Player owner;
	protected List<Conquest> conquests;
	protected long nextUpdateTime;
	
//	public static final int CAPACITY = 40;
	public static final int UPDATE_TIME_GAP = 10 * 60 * 1000;//10 * 60 * 1000;
	protected static final Logger LOG = ConquestsService.LOG;
	
	public Conquests() {}
	
	public Conquests(Player player, List<Conquest> conquests) {
		this.owner = player;
		this.conquests = conquests;
		for (int i = 0, size = conquests != null ? conquests.size() : 0; i < size; i++) {
			Conquest c = conquests.get(i);
			c.vm = this;
		}
	}

	public Player getOwner() {
		return owner;
	}

	public void setOwner(Player owner) {
		this.owner = owner;
	}

	public List<Conquest> getConquests() {
		return conquests;
	}
	
	public int size() {
		return conquests != null ? conquests.size() : 0;
	}
	
	public boolean isFull() {
		return size() >= VipUtils.getTemplate(owner.getVipLvl()).getCaptureBuildMaxCount();//GameStaticConfig.captureBuildMaxCount;
	}
	
	public int sizeByTarget(Player target) {
		if (conquests == null) {
			return 0;
		}
		int size = 0;
		for (int i = conquests.size() - 1; i >= 0; i--) {
			Conquest c = conquests.get(i);
			if (c.getOwnerId() == target.getId()) {
				++size;
			}
		}
		return size;
	}
	
	@Deprecated
	public synchronized Conquest remove(Build build) {
		if (conquests == null) {
			return null;
		}
		long ownerId = build.getManager().getOwner().getId();
		int buildId = build.getId();
		for (int i = conquests.size() - 1; i >= 0; i--) {
			Conquest c = conquests.get(i);
			if (c.getOwnerId() == ownerId && c.getId() == buildId) {
				c.clear();
				conquests.remove(i);
				owner.send(new IntSync(SyncPush.SYNC_CONQUESTS_COUNT, size()));
				return c;
			}
		}
		return null;
	}
	
	public synchronized Conquest remove(BuildV2 build, boolean needCalcMoney) {
		if (conquests == null) {
			return null;
		}
		long ownerId = build.getVm().getOwner().getId();
		int buildId = build.getId();
		for (int i = conquests.size() - 1; i >= 0; i--) {
			Conquest c = conquests.get(i);
			if (c.getOwnerId() == ownerId && c.getId() == buildId) {
				if(needCalcMoney){
					int[] moneyInfo = c.calcMoney(build.getTemplate().getProduceMoneyFactor(), BuildV2.MAX_TAKE_MONEY_SECOND);
					if(moneyInfo[0] > 0){
						MailAttach attach = new MailAttach();
						attach.setGold(moneyInfo[0]);
						App.getApp().getServiceManager().get(MailService.class).sendSystemMail(
								owner.getId(),
								MessageConst.BUILD_UNCAPTURE_SETTLE_MAIL_TITLE,
								MessageConst.BUILD_UNCAPTURE_SETTLE_MAIL_TITLE,
								attach);
					}
				}
				c.clear();
				conquests.remove(i);
				owner.fireFixedAssetsChanged();
				owner.send(new IntSync(SyncPush.SYNC_CONQUESTS_COUNT, size()));
				return c;
			}
		}
		return null;
	}
	
	@Deprecated
	public synchronized Conquest add(Build build, List<Employee> defenders) {
		if (conquests == null) {
			conquests = new ArrayList<Conquest>();
		}
		Conquest c = new Conquest(this, build, defenders);
		conquests.add(c);
		owner.send(new IntSync(SyncPush.SYNC_CONQUESTS_COUNT, size()));
		return c;
	}
	
	public synchronized Conquest add(BuildV2 build, List<Employee> defenders) {
		if (conquests == null) {
			conquests = new ArrayList<Conquest>();
		}
		Conquest c = new Conquest(this, build, defenders);
		conquests.add(c);
		owner.fireFixedAssetsChanged();
		owner.send(new IntSync(SyncPush.SYNC_CONQUESTS_COUNT, size()));
		return c;
	}
	
	public Conquest find(long ownerId, int buildId) {
		if (conquests == null) {
			return null;
		}
		for (int i = 0, size = conquests.size(); i < size; i++) {
			Conquest c = conquests.get(i);
			if (c.getOwnerId() == ownerId && c.getId() == buildId) {
				return c;
			}
		}
		return null;
	}
	
	public Conquest findByEmployee(Employee employee) {
		if (conquests == null) {
			return null;
		}
		for (int i = 0, size = conquests.size(); i < size; i++) {
			Conquest c = conquests.get(i);
			long[] eids = c.getEmployees();
			for (long eid : eids) {
				if (eid == employee.getId()) {
					return c;
				}
			}
		}
		return null;
	}

	@Override
	public String toString() {
		return JSON.toJSONString(conquests != null ? conquests : Collections.emptyList());
	}

	@Override
	public boolean update() {
		long now = TimeUpdater.getInstance().now();
		if (now > nextUpdateTime) {
			update0(now);
		}
		return true;
	}
	
	private synchronized void update0(long timestamp) {
		nextUpdateTime = timestamp + UPDATE_TIME_GAP;
		if (size() == 0) {
			return;
		}
		PlayerCacheService service = App.getApp().getServiceManager().get(PlayerCacheService.class);
		for(int i = size() - 1; i >= 0; i--){ // must reverse, ignore array index out of bounds exception
			Conquest c = conquests.get(i);
			Player p = service.find(c.ownerId);
			if(p != null){
				BuildV2 b = p.getBuildings2().find(c.getId());
				if(b != null){
					if(b.getInvaderId() == this.getOwner().getId()){
						if(b.getLastCapureTime() > 0){
							if(timestamp > b.getLastCapureTime() + BuildV2.BUILD_RETURN_MILLISECOND){
								if(b.getState() == BuildV2.State.CAPTURED){
									b.unCapture(this.getOwner(), Cause.AUTO, true);
								}
							}
						}else{
							b.setLastCapureTime(timestamp);
						}
					}
				}
			}
		}
	}

	@Override
	public void fireEmployeeRemoved(Employee employee) {
		State state = State.CAPTURE;
		if (!state.enable || employee.getState() == state) {
			for (int i = 0, size = conquests.size(); i < size; i++) {
				Conquest c = conquests.get(i);
				if (c.removeEmployee(employee.getId())) {
					break;
				}
			}
		}
	}

	@Override
	public void write(SerializeStream out) {
		SerializerUtils.serialize(this, out);
	}
	
}
